45장. Task Definition 깊게 보기
이 장에서 말하고자 하는 것
운영에서 가장 자주 만지는 게 Task Definition이다.
새 버전 배포 = 새 Task Definition 리비전 등록
이 장은 Task Definition의 주요 필드를 정리한다.
1. 주요 필드
family : 이름 (orders, users 등)
revision : 자동 증가 번호 (1, 2, 3 …)
networkMode : awsvpc (Fargate는 항상 이거)
cpu / memory : Task 전체 자원
executionRoleArn : Task를 띄울 때 필요한 권한
taskRoleArn : Task 안의 코드가 AWS API 호출할 때 권한
containerDefinitions : 컨테이너 한 대 이상의 정의
2. Family와 Revision
orders:1, orders:2, orders:3 ...
새 버전 배포:
이미지 push → 새 revision 등록 → Service가 그 revision으로 업데이트
orders:2 가 망가지면 Service에 orders:1 을 다시 지정해 롤백.
모든 revision은 보존된다 — 롤백 자산이다
3. CPU와 Memory
Fargate는 묶음으로 고른다.
0.25 vCPU → 512 MB / 1 GB / 2 GB
0.5 vCPU → 1 ~ 4 GB
1 vCPU → 2 ~ 8 GB
2 vCPU → 4 ~ 16 GB
묶음 밖의 조합은 불가.
너무 작게 잡으면 OOM, 너무 크게 잡으면 비용
4. Container Definition
container "app"
├─ image : ECR URL
├─ portMappings
├─ environment / secrets
├─ logConfiguration
├─ healthCheck
├─ essential : true/false
└─ dependsOn : 사이드카 순서
essential
essential = true → 이 컨테이너 죽으면 Task 전체 죽음
essential = false → 죽어도 Task는 살아 있음
메인 앱은 true.
5. 환경 변수와 시크릿
"environment": [
{ "name": "PORT", "value": "8080" }
]
"secrets": [
{ "name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:...:secret:db/password" }
]
비밀은 Task Definition 안에 평문으로 두지 않는다
6. 로그 설정
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/orders",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "app"
}
}
7. Execution Role vs Task Role
가장 헷갈리는 두 권한.
Execution Role
→ "Task를 띄우기 위해" 필요
→ ECR pull, CloudWatch Logs 쓰기, Secrets Manager 읽기
→ ECS 에이전트가 사용
Task Role
→ "Task 안 코드" 가 AWS API 호출할 때 권한
→ S3 읽기, DynamoDB 접근 등
→ 애플리케이션이 사용
이 둘을 헷갈리면
- “Task가 시작 안 됨” → Execution Role 문제
- “Task는 떴는데 S3 권한 거부됨” → Task Role 문제
8. 우리 서비스에서
orders 의 Task Definition은 대략:
family: orders
cpu: 512 / memory: 1024
executionRoleArn: ecs-task-execution-role
taskRoleArn: orders-task-role (DynamoDB 읽기 권한)
container "app"
image: <ecr>/orders:v1
portMapping: 8080
environment: PORT=8080
secrets: DB_PASSWORD ← Secrets Manager
logConfig: awslogs → /ecs/orders
같은 패턴을 users · payments 로 복제.
9. 직접 확인해보기 — CLI
aws ecs register-task-definition \
--cli-input-json file://task-def.json
aws ecs describe-task-definition \
--task-definition orders
aws ecs describe-task-definition \
--task-definition orders:5
10. 코드로는 이렇게 생겼다 — Terraform
resource "aws_ecs_task_definition" "orders" {
family = "orders"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "512"
memory = "1024"
execution_role_arn = aws_iam_role.task_execution.arn
task_role_arn = aws_iam_role.orders_task.arn
container_definitions = jsonencode([{
name = "app"
image = "${aws_ecr_repository.orders.repository_url}:v1"
essential = true
portMappings = [
{ containerPort = 8080, protocol = "tcp" }
]
environment = [
{ name = "PORT", value = "8080" }
]
secrets = [
{ name = "DB_PASSWORD",
valueFrom = aws_secretsmanager_secret.db_password.arn }
]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = "/ecs/orders"
awslogs-region = "ap-northeast-2"
awslogs-stream-prefix = "app"
}
}
}])
}
11. 이렇게 쓰면 망한다 — 안티패턴
안티패턴 1. 비밀을 평문 환경 변수에 둔다
secrets 로 Secrets Manager에서 가져온다.
안티패턴 2. Execution Role과 Task Role을 혼동한다
같은 Role을 두 자리에 박으면 권한이 과해진다.
두 Role은 별도로, 각자의 최소 권한만
안티패턴 3. revision을 안 정리한다
수십 개의 revision이 쌓여 검색이 어려워진다. 주기적으로 deregister.
안티패턴 4. CPU/메모리를 한 번 잡고 안 본다
실측 후 조정한다.
12. 한 줄로 정리
Task Definition은 컨테이너의 설계도이며,
family + revision 단위로 모든 배포와 롤백이 일어난다
13. 이 장의 핵심 정리
- family + revision 이 Task Definition의 식별자다.
- CPU/메모리는 Fargate 허용 묶음 안에서만.
- Execution Role은 Task 시작용, Task Role은 Task 내부 코드용.
- 비밀은
secrets로 Secrets Manager에서 주입한다. - revision은 모두 보존된다 — 곧 롤백 자산.
- 실측 기반으로 CPU/메모리를 주기적으로 조정한다.